おなかソフトのDon't Destroy On Load #1に行ってきた
概要
このこれ
Drecom Tech Espresso #6 "おなかソフトのDontDestroyOnLoad"
https://drecom.connpass.com/event/93534/
当日の様子はなんか動画として上がるようなので期待して待ってる。
あとは全部おまけというかとりあえず事前に考えをまとめておこうと思って書いたアンチョコ(アバターのフェイスキャプチャが繊細すぎて本当に目が離せなくて全く見れなかった。(ちょっと文がぶっちぎれ過ぎているので捕捉した。
ゲームのSingletonどう思う?
直感的には、ゲーム要素に関して何か保持しているシングルトンは、8割くらいで負債になる、設計の放棄。
ようは 状態を持った グローバル関数 なので、そりゃやばかろうよという感じになると思う。
Sigletonを使うと可換性にものすごい問題を来たす。アクセスが容易すぎるんで、いろんなところから接続できて、その前提を元にコードが書かれる。
ここで問題なのは、安易に接続させてしまうことで、接続する側が後世に渡って受ける設計的な影響力が大きすぎること。
「どうすれば可換な状態を維持できるか」というのに注目すると、ゲーム内Singleton作ってもすぐ捨てないとだめみたいな気分になると思う。
逆に、目的が「それ」 = どこからでもアクセスできてしかるべきもの、ならば存在してアリだとは思っている。(サウンドマネージャとか認証系とかリソースロード系とか、ゲームのコア以外の部分のデータの持ち回しとか)
Autoyaもそんな感じで、あれは認証 + Asset管理 + サーバからのバージョンコントロールを行うための「状態」を保持したシングルトンになっている。
リセッタとか完備してあったり作り直せるようになってるのでテストできる。
だが、やはり「ゲームの、まさに遊ばせるためのコードの中身」ではない。脇役なのでこの構造を許している。
Unity + ゲーム内Singletonでよくある悪
テストの邪魔
全てのタイミングを貫通して状態を持ってしまう + 閉鎖的、というのがネック。
毎回作り直すためにプログラムのコンテキスト自体を作り直すとかの力技が必要
欲しいのはSingleton? それとも一定区間だけアクセス可能なステートマシン?
本来あるべきではない公開度合いと、それによる密結合
どこからでもアクセスできる、というのがまず設計的な間違いとして露見してくるパターンがほとんどで、
実際に必要だったのはもっと小さなスコープ、もっと狭いアクセス範囲ということが多い。
だのにグローバルに置いてしまって、「今シングルトンを止めるには、シングルトンに依存している側を大規模に書き直さないといけない」などが発生する。
つまりシングルトンは「将来のコードの変更可能性を下げる」楔なのだ。
グローバルではなく、何らかの関係性の何らかのタイミングへの隠蔽、みたいなのが理想で、これは最初からグローバルで作ってしまうと後から直すのが大変。
SingleMonoBe
自分は一切お世話になったことがないのでよくわからない。だいたいシーンごとに用意した代替を使ってしまう。
MonoBeが必要なポイントは後述するが、限られているので、こう、はい。
おまけ:MonoBehaviourの使い所について考えよう
・Unityと開発者をつなぐ場所
・メインスレッドへのエントリーポイント
-> つまりメインスレッドでしかできないことをするための場所
それだけのためにMBがあればいいのではというね。
昨今はおもしろコンパイラやおもしろシステムもあることだし、この考え方は変わらないのかなあと思っている。C#で書く場所で頑張らない。
Unityのメインスレッド制約
GUI操作、オーディオ、コンポーネントへの干渉などの起点はすべてこの制約がある。
この制約のせいで、グローバルからこういう操作呼びたいな~~ってなると、どうしてもMonoBehaviourが必要になる。
で、これをグローバルに一個だけ置ければいいのでは -> 状態も持たせちゃおう(バカ) -> つらい、、
Updateとか一個の方が良くない?
いい話。でもこれを解決するのはSingletonではなく、現在のゲームのコンテキストに対して一個あるだけのもの、とかで良いはず。
というかMonoBehaviourを拡張するな。あれはこう、、色々な用途を持つ、UnityとC#コード(というか開発者がやりたいこと全て)をつなぐブリッジ部分だ。
みたいなことを思うことは割とあるけど、まあ人の数だけ正義があるので、正しさ~みたいな話はしない。ほら、人の正義とかどうでもいいじゃないですか。
それでも避けられない、みんなが欲しい、Unity + Singletonに求められるもの
MainThreadDispatcher
俺は!! ここから!! メインスレッドに!! 何かを投げ込みたい!!!
例えばiOSとかだとそういうの簡単にできるんだ。本当にどこからでも簡単に。
でもUnityにはそういうのないんで。誰かが作って、それをグローバルにおいて、っていうのがよくある。
UniRxとかな。
4.6が使えるようになる + SynchronizationContextがあるじゃん! っていうのははい、ありますが、
どこかで取得してグローバルにしないといけないのですよね。はい。
俺は無手でメインスレッドに放り込むようなものが標準でなんもせんで欲しいのだよ。(iOSとかそのへんで存在してて便利)
オーディオエンジン
オーディオの再生制約にメインスレッド必須があるせいで、どこかのオーディオエンジン使う以外だとシングルトン作って済ませてしまうことが多い。